﻿using System;
using System.Text;
using System.Threading;

namespace Fortune.Log
{
    /// <summary>
    /// Java风格的日志打印
    /// </summary>
    public class FortuneLogger
    {
        /// <summary>
        /// 日期打印格式
        /// </summary>
        private readonly string dateFormat;
        /// <summary>
        /// logger所在类
        /// </summary>
        private readonly Type currentType;
        /// <summary>
        /// 线程文本长度限制
        /// </summary>
        private const int THREAD_TEXT_LENGTH = 16;
        /// <summary>
        /// 类文本长度限制
        /// </summary>
        private const int TYPE_TEXT_LENGTH = 32;
        
        private FortuneLogger(Type currentType, string dateFormat = @"yyyy-MM-dd HH:mm:ss")
        {
            this.currentType = currentType;
            this.dateFormat = dateFormat;
        }

        public static FortuneLogger newInstance(Type currentType, string dateFormat = @"yyyy-MM-dd HH:mm:ss")
        {
            return new FortuneLogger(currentType, dateFormat);
        }

        public void info(string message)
        {
            Console.Out.WriteLine($"{getLogPrefix()}{message}");
        }

        public void debug(string message)
        {
            Console.Out.WriteLine($"{getLogPrefix(LogLevel.DEBUG)}{message}");
        }

        public void warning(string message)
        {
            Console.Out.WriteLine($"{getLogPrefix(LogLevel.WARNING)}{message}");
        }

        public void error(string message)
        {
            Console.Out.WriteLine($"{getLogPrefix(LogLevel.ERROR)}{message}");
        }
        
        public void error(string message, Exception e)
        {
            error(message);
            Console.Out.WriteLine(e);
        }
        
        /// <summary>
        /// 生成日志前缀，包含日期、日志等级、当前线程名称、当前类名称
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        private string getLogPrefix(LogLevel level = LogLevel.INFO)
        {
            return $"{dateText()} - {levelText(level), 7} --- [{threadText(), THREAD_TEXT_LENGTH}] {typeText(), TYPE_TEXT_LENGTH} : ";
        }
        
        /// <summary>
        /// 生成日期字符串
        /// </summary>
        /// <returns></returns>
        private string dateText()
        {
            return DateTime.Now.ToString(dateFormat);
        }
        
        /// <summary>
        /// 生成日志等级字符串
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        private static string levelText(LogLevel level)
        {
            return Enum.GetName(typeof(LogLevel), level);
        }
        
        /// <summary>
        /// 生成当前线程字符串
        /// </summary>
        /// <returns></returns>
        private static string threadText()
        {
            string currentThreadName = Thread.CurrentThread.Name;
            string threadId = Thread.CurrentThread.ManagedThreadId.ToString();
            return limitStringLength(currentThreadName ?? $"DEFAULT-{threadId}", THREAD_TEXT_LENGTH);
        }
        
        /// <summary>
        /// 生成类型字符串，全名过长时会被缩写
        /// for example：System.IO.File => S.I.F
        /// </summary>
        /// <returns></returns>
        private string typeText()
        {
            string fullName = currentType.FullName;
            if (fullName == null)
            {
                return null;
            }

            if (fullName.Length <= TYPE_TEXT_LENGTH)
            {
                return fullName;
            }
            string[] strings = fullName.Split('.');
            int arrLength = strings.Length;
            if (arrLength < 2)
            {
                return limitStringLength(fullName, TYPE_TEXT_LENGTH);
            }

            StringBuilder sb = new StringBuilder(strings[0].Substring(0, 1));
            if (arrLength == 2)
            {
                sb.Append(strings[1]);
                return limitStringLength(sb.ToString(), TYPE_TEXT_LENGTH);
            }
            for (int i = 1; i < arrLength - 1; i++)
            {
                sb.Append(".");
                sb.Append(strings[i].Substring(0, 1));
            }

            sb.Append(".");
            sb.Append(strings[arrLength - 1]);
            
            return limitStringLength(sb.ToString(), TYPE_TEXT_LENGTH);
        }
        
        /// <summary>
        /// 限制字符串长度，超过长度的字符串会将其限定长度内的后三位替换为“...”
        /// for example："123456789", 限制长度为6 => "123..."
        /// </summary>
        /// <param name="message"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private static string limitStringLength(string message, int length)
        {
            if (message == null || length < 1)
            {
                return message;
            }

            return message.Length <= length ? message : $"{message.Substring(0, length - 3)}...";
        }
    }

    /// <summary>
    /// 日志等级枚举
    /// </summary>
    public enum LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR
    }
}